package org.ricks.ioc.scheduler;

import org.ricks.ioc.HotfixManager;
import org.ricks.ioc.event.CronEvent;
import org.ricks.ioc.event.DelayEvent;
import org.ricks.ioc.event.FixRateEvent;
import org.ricks.ioc.event.IEvent;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.UUID;

/**
 * 调度任务定义类，封装任务元数据与执行逻辑
 * 实现Comparable接口用于优先队列排序
 */
public class SchedulerDefinition implements Comparable<SchedulerDefinition> {
    // 下次触发时间戳（毫秒）
    private volatile long triggerTimestamp;
    // 任务执行逻辑包装器
    private IScheduler scheduler;
    // 任务唯一标识（类名+方法名）
    private String taskId;
    //触发器
    private DelayTrigger trigger;

    private volatile boolean cancelled;
    private ScheduleType scheduleType;

    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }

    /**
     * 自定义失败重试
     * @return
     */
    public boolean checkRetry() {
        return false;
    }

    enum ScheduleType {
        FIXED_RATE, DELAY, CRON
    }

    // 修改构造方法，支持外部传入taskId
    public SchedulerDefinition(String taskId) {
        this.taskId = taskId != null ? taskId : UUID.randomUUID().toString();
    }

    public SchedulerDefinition(long triggerTimestamp) {
        this.triggerTimestamp = triggerTimestamp;
    }

    public SchedulerDefinition() {
        this(null);
    }

    // 添加统一的任务ID生成方法
    private static String generateTaskId(Object target, Method method) {
        return target.getClass().getName() + "#" + method.getName();
    }

    /**
     * 构造方法 - Cron模式
     */
    public static SchedulerDefinition valueOf(String cron, Object target, Method method) throws Throwable {
        Objects.requireNonNull(cron, "Cron表达式不能为空");
        Objects.requireNonNull(target, "目标对象不能为空");
        Objects.requireNonNull(method, "方法不能为空");
        String taskId = generateTaskId(target, method);
        var schedulerDef = new SchedulerDefinition(taskId);
        schedulerDef.init(ScheduleType.CRON,new CronTrigger(cron), enhance(target, method));
        return schedulerDef;
    }

    /**
     * 构造方法 - FixedRateTrigger模式
     */
    public static SchedulerDefinition valueOf(long initialDelay, long period, Object target, Method method) throws Throwable {
        String taskId = generateTaskId(target, method);
        var schedulerDef = new SchedulerDefinition(taskId);
        schedulerDef.init(ScheduleType.FIXED_RATE,new FixedRateTrigger(initialDelay, period), enhance(target, method));
        return schedulerDef;
    }

    /**
     * 构造方法 - FixedRateTrigger模式
     */
    public static SchedulerDefinition valueOf(long delay, Object target, Method method) throws Throwable {
        String taskId = generateTaskId(target, method);
        var schedulerDef = new SchedulerDefinition(taskId);
        schedulerDef.init(ScheduleType.DELAY,new DelayTrigger(System.currentTimeMillis() + delay), enhance(target, method));
        return schedulerDef;
    }

//    private static IScheduler enhance( Object target, Method method) throws Throwable {
//        if (Runtime.version().feature() < 24) {
//            return ReflectScheduler.valueOf(target, method);
//        }
//        return EnhanceUtils.createScheduler(ReflectScheduler.valueOf(target, method));
//    }

    /**
     * 构造方法 - Cron模式
     */
    public static SchedulerDefinition createCronJob(String cron,Runnable task) {
        var schedulerDef = new SchedulerDefinition();
        schedulerDef.init(ScheduleType.CRON,new CronTrigger(cron), RunnableScheduler.valueOf(task));
        return schedulerDef;
    }

    /**
     * 构造方法 - 固定频率模式
     */
    public static SchedulerDefinition createFixJob(long initialDelay, long period, Runnable task) {
        if (period <= 0) {
            throw new IllegalArgumentException("Period must be positive");
        }
        var schedulerDef = new SchedulerDefinition();
        schedulerDef.init(ScheduleType.FIXED_RATE,new FixedRateTrigger(initialDelay, period), RunnableScheduler.valueOf(task));
        return schedulerDef;
    }

    public static SchedulerDefinition createDelayJob(long delay,  Runnable task) {
        var schedulerDef = new SchedulerDefinition();
        schedulerDef.init(ScheduleType.DELAY, new DelayTrigger(System.currentTimeMillis() + delay), RunnableScheduler.valueOf(task));
        return schedulerDef;
    }

    public static SchedulerDefinition createDelayEventJob(IEvent event) {
        var schedulerDef = new SchedulerDefinition();
        switch (event) {
            case FixRateEvent fixRateEvent -> schedulerDef.init(ScheduleType.FIXED_RATE,new FixedRateTrigger(fixRateEvent.getInitialDelay(), fixRateEvent.getPeriod()), EventScheduler.valueOf(event));
            case CronEvent cronEvent -> schedulerDef.init(ScheduleType.CRON,new CronTrigger(cronEvent.getCronExpression()), EventScheduler.valueOf(event));
            case DelayEvent delayEvent -> schedulerDef.init(ScheduleType.DELAY,
                    new DelayTrigger(System.currentTimeMillis() + delayEvent.delayTime()), EventScheduler.valueOf(event));
            default -> throw new IllegalArgumentException("Unsupported event type: " + event.getClass().getName());
        }
        return schedulerDef;
    }

    private void init(ScheduleType scheduleType,DelayTrigger trigger, IScheduler scheduler) {
        this.scheduleType = scheduleType;
        this.trigger = trigger;
        this.scheduler = scheduler;
        this.triggerTimestamp = trigger.triggerTime();
    }

    private static IScheduler enhance(Object target, Method method) throws Throwable {
        // 热更类直接使用反射方式，避免增强方式的问题
        if (Runtime.version().feature() < 24 || HotfixManager.isHotfixClass(target.getClass())) {
            return ReflectScheduler.valueOf(target, method);
        }
        return EnhanceUtils.createScheduler(ReflectScheduler.valueOf(target, method));
    }


    /**
     * 更新下次触发时间（固定频率模式）
     */
    public boolean updateNextTriggerTime() {
        this.triggerTimestamp = this.trigger.triggerTime();
        return scheduleType != ScheduleType.DELAY;
    }

    public void cancel() {
        this.cancelled = true;
    }

    // 实现优先队列比较逻辑
    @Override
    public int compareTo(SchedulerDefinition other) {
        return Long.compare(this.triggerTimestamp, other.triggerTimestamp);
    }

    //----------------- Getter/Setter -----------------
    public long getTriggerTimestamp() {
        return triggerTimestamp;
    }

    public void setTriggerTimestamp(long triggerTimestamp) {
        this.triggerTimestamp = triggerTimestamp;
    }

    public IScheduler getScheduler() {
        return scheduler;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public void setCancelled(boolean cancelled) {
        this.cancelled = cancelled;
    }

    public String getTaskId() {
        return taskId;
    }

    public void calibrateTime(long currentTime) {
    }
}